﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using YoutubeExtractor;

namespace ExampleApplication
{
	internal class Program
	{
		private static void DownloadAudio(IEnumerable<VideoInfo> videoInfos)
		{
			/*
			 * We want the first extractable video with the highest audio quality.
			 */
			VideoInfo video = videoInfos
				.Where(info => info.CanExtractAudio)
				.OrderByDescending(info => info.AudioBitrate)
				.First();

			/*
			 * Create the audio downloader.
			 * The first argument is the video where the audio should be extracted from.
			 * The second argument is the path to save the audio file.
			 */

			var audioDownloader = new AudioDownloader(video,
			                                          Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), RemoveInvalidFileName(video.Title) + video.AudioExtension));

			// Register the progress events. We treat the download progress as 85% of the progress
			// and the extraction progress only as 15% of the progress, because the download will
			// take much longer than the audio extraction.
			audioDownloader.DownloadProgressChanged += (sender, args) => Console.WriteLine("Audio download progress: " + args.ProgressPercentage * 0.85);
			audioDownloader.AudioExtractionProgressChanged += (sender, args) => Console.WriteLine("Audio Extraction download progress: " +(85 + args.ProgressPercentage * 0.15));
			audioDownloader.DownloadFinished += (sender, args) => Console.WriteLine("Audio " + video.Title + video.AudioExtension +"finish");
			/*
			 * Execute the audio downloader.
			 * For GUI applications note, that this method runs synchronously.
			 */
			audioDownloader.Execute();
		}

		private static void DownloadVideo2(IEnumerable<VideoInfo> videoInfos)
		{
			/*
			 * Select the first .mp4 video with 360p resolution
			 */
			//var t1 = videoInfos.Where(info => info.CanExtractAudio);
			// var t2 = videoInfos.Where(info => info.CanExtractAudio).Where(info => info.VideoType == VideoType.Mp4);
			VideoInfo video = videoInfos
				//.Where(info => info.CanExtractAudio)
				.First(info => info.VideoType == VideoType.Mp4 && info.Resolution == 480);

			/*
			 * Create the video downloader.
			 * The first argument is the video to download.
			 * The second argument is the path to save the video file.
			 */
			string filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), RemoveInvalidFileName(video.Title) + video.VideoExtension);
			var videoDownloader = new VideoDownloader(video,
			                                          filePath);

			// Register the ProgressChanged event and print the current progress
			videoDownloader.DownloadProgressChanged += (sender, args) => Console.WriteLine("Video download progress: " + args.ProgressPercentage);
			videoDownloader.DownloadFinished += (sender, args) => Console.WriteLine("Video " + video.Title + video.VideoExtension +" finish");
			/*
			 * Execute the video downloader.
			 * For GUI applications note, that this method runs synchronously.
			 */
			videoDownloader.Execute();
			
		}
		
		private static void ExtractAudio(VideoInfo video)
		{
			string videoPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), video.Title + video.VideoExtension);
			string audioPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), video.Title + video.AudioExtension);
			using (var flvFile = new FlvFile(videoPath, audioPath))
			{
				flvFile.ConversionProgressChanged += (sender, args) =>
				{
					Console.WriteLine("Audio Extraction download progress: " +(85 + args.ProgressPercentage * 0.15));
				};

				flvFile.ExtractStreams();
			}
		}
		
		private static void DownloadVideo(IEnumerable<VideoInfo> videoInfos)
		{
			/*
			 * Select the first .mp4 video with 360p resolution
			 */
			//var t1 = videoInfos.Where(info => info.CanExtractAudio);
			// var t2 = videoInfos.Where(info => info.CanExtractAudio).Where(info => info.VideoType == VideoType.Mp4);
			VideoInfo video = videoInfos
				.Where(info => info.CanExtractAudio).OrderByDescending(o=>o.Resolution)
				.First();

			/*
			 * Create the video downloader.
			 * The first argument is the video to download.
			 * The second argument is the path to save the video file.
			 */
			string filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), RemoveInvalidFileName(video.Title) + video.VideoExtension);
			var videoDownloader = new VideoDownloader(video,
			                                          filePath);

			// Register the ProgressChanged event and print the current progress
			videoDownloader.DownloadProgressChanged += (sender, args) => Console.WriteLine("Video download progress: " + args.ProgressPercentage);
			videoDownloader.DownloadFinished += (sender, args) => 
			{
				Console.WriteLine("Video " + video.Title + video.VideoExtension +" finish");
				ExtractAudio(video);
			};
			/*
			 * Execute the video downloader.
			 * For GUI applications note, that this method runs synchronously.
			 */
			videoDownloader.Execute();
			
		}

		private static void Main()
		{
			// Our test youtube link
			string link = "https://www.youtube.com/watch?v=7YtD86bio5U";
			string link2 = "https://www.youtube.com/watch?v=SFA6qhZwLLM";
			List<string> links = new List<string>();
			links.Add(link);
			links.Add(link2);
			/*
			 * Get the available video formats.
			 * We'll work with them in the video and audio download examples.
			 */
			
			foreach (var sLink in links) {
			IEnumerable<VideoInfo> videoInfos = DownloadUrlResolver.GetDownloadUrls(link);
//			DownloadVideo(videoInfos);
			DownloadVideo(videoInfos);
			}
			
			Console.WriteLine("All done!");
			Console.ReadLine();
		}
		
		private static string RemoveInvalidFileName(string input)
		{
			string invalid = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
			foreach (char c in invalid)
			{
				input = input.Replace(c.ToString(), "");
			}
			return input;
		}
	}
}